import java.io.ByteArrayInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;


public class Controle {

public HashMap<String,Integer> argFctPredefinie = new HashMap<String,Integer>();
	
	public HashMap<String,Method> methodFctPredefinie = new HashMap<String,Method>();
	
	public Controle() {
		argFctPredefinie.put("si", 2);
		argFctPredefinie.put("sinon", 3);
		argFctPredefinie.put("repete", 2);
		argFctPredefinie.put("locale", 2);
		argFctPredefinie.put("chose", 1);
		argFctPredefinie.put("ecris", 1);
		argFctPredefinie.put("tantque", 2);
		argFctPredefinie.put("repetepour", 2);
		
		Class c = Controle.class;
		Method[] tab = c.getMethods();
		
		Method  m;
		for (int i=0;i<tab.length;i++) {
			m = tab[i];
	
			if(m.getName().equals("si"))
				methodFctPredefinie.put("si", m);
			
			if(m.getName().equals("sinon"))
				methodFctPredefinie.put("sinon", m);
			
			if(m.getName().equals("repete"))
				methodFctPredefinie.put("repete", m);
			
			if(m.getName().equals("locale"))
				methodFctPredefinie.put("locale", m);
			
			if(m.getName().equals("chose"))
				methodFctPredefinie.put("chose", m);
			
			if(m.getName().equals("ecris"))
				methodFctPredefinie.put("ecris", m);
			
			if(m.getName().equals("tantque"))
				methodFctPredefinie.put("tantque", m);
			
			if(m.getName().equals("repetepour"))
				methodFctPredefinie.put("repetepour", m);
		}    
	};
	
	
	public static String listToString(ArrayList l){
		String list = "[ ";
		
		for(int i=0; i<l.size();i++){
			if(l.get(i) instanceof ArrayList)
				list += listToString((ArrayList)l.get(i))+" ";
			else
				list += l.get(i) +" ";
		}
		list += "]";
		return list;
	}
	
	public static Object run(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
			
		String list = (String)v.get(0);
		
		list = list.substring(1, list.length()-1);
		//System.out.println("stream : "+list);
		ByteArrayInputStream stream  = new ByteArrayInputStream(list.getBytes());

        Logo parser = new Logo(stream);
        parser.initEnv(penv);
        
        return parser.run();
	}
	
	
	public static Object si(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		ArrayList<Object> o = new ArrayList<Object>();

		HashMap<String, Object> env = new HashMap<String, Object>();
		
		env.put("env_sup",penv);
		
		if((v.get(0) instanceof Boolean)  && v.get(1) instanceof ArrayList  && v.size()==2) {
			if ((Boolean)v.get(0)){
				o.add(listToString((ArrayList)v.get(1)));
				return run(o,env);
			}
			else
				return false;
		}
		else
			return false;
	}
	
	
	public static Object sinon(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		ArrayList<Object> o = new ArrayList<Object>();
		
HashMap<String, Object> env = new HashMap<String, Object>();
		
		env.put("env_sup",penv);
		
		if((v.get(0) instanceof Boolean)  && v.get(1) instanceof ArrayList  && v.size()==3) {
			if ((Boolean)v.get(0)) {
				o.add(listToString((ArrayList)v.get(1)));
				return run(o,env);
			}
			else {
				if(v.get(2) instanceof ArrayList) {
					o.add(listToString((ArrayList)v.get(2)));
					return run(o,env);
				}
				return false;
			}
		}
		else
			return false; 
	}
	
	
	public static Object repete(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		ArrayList<Object> o = new ArrayList<Object>();
		Object ret = null;
		
		HashMap<String, Object> env = new HashMap<String, Object>();
		env.put("env_sup",penv);
		
		if((v.get(0) instanceof Integer)  && v.get(1) instanceof ArrayList  && v.size()==2) {
			o.add(listToString((ArrayList)v.get(1)));
		
			for(int i=0; i<(Integer)v.get(0); i++) 
				ret = run(o,env);
		}
			
		return ret;
	}
	
	
	public static Object locale(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if((v.get(0) instanceof String) && v.size()==2) {
			if(locale2((String)v.get(0),v.get(1),penv) == false) {
				penv.put((String)v.get(0),v.get(1));
				return true;
			}
			else return false;
		}
		else return false;
	}
	
	public static boolean locale2(String cle, Object val,  HashMap<String, Object> penv) throws ParseException, Exception{
		
	
			if(penv.containsKey(cle)) {
				penv.put(cle,val);
				return true;
			}
			else
				if(penv.containsKey("env_sup")) {
				return locale2(cle,val,(HashMap)penv.get("env_sup"));
				}
				else
					return false;
	}
	
	
	public static Object chose(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		
		if((v.get(0) instanceof String) && v.size()==1)
			if (penv.containsKey((String)v.get(0)))
				return penv.get((String)v.get(0));
			else
				if(penv.containsKey("env_sup"))
					return chose(v,(HashMap)penv.get("env_sup"));
				else 
					throw new Error("la variable "+(String)v.get(0)+" n'est dans l'env");
		else
			throw new Error("la variable "+(String)v.get(0)+" n'est dans l'env");
		}
	
	
	public  static Object ecris(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
	
		if(v.size()==1) {
			if(v.get(0) instanceof ArrayList) 
				System.out.println(listToString((ArrayList)v.get(0)));
			else
				System.out.println(v.get(0));
			return true;
		}
		else 
			return false;
		
	}
	
	
	public static Object tantque(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		ArrayList<Object> o = new ArrayList<Object>();
		ArrayList<Object> o2 = new ArrayList<Object>();
		Object ret = null;

		HashMap<String, Object> env = new HashMap<String, Object>();
		
		env.put("env_sup",penv);
		
		if(v.size() == 2 && v.get(0) instanceof ArrayList && v.get(1) instanceof ArrayList) {
			o.add(listToString((ArrayList)v.get(0)));
			o2.add(listToString((ArrayList)v.get(1)));
			while((Boolean)run(o,env)) {
				ret = run(o2,env);
			}
		}
			
		return ret;
	}
	
	
	public static Object repetepour(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		ArrayList<Object> o = new ArrayList<Object>();
		ArrayList<Object> l = new ArrayList<Object>();
		Object ret = null;
		
		HashMap<String, Object> env = new HashMap<String, Object>();
		
		env.put("env_sup",penv);
		
		if(v.size() == 2 && v.get(0) instanceof ArrayList && v.get(1) instanceof ArrayList) {
			l = s(ArrayList)v.get(0);
			if(l.size() == 3 || l.size() == 4){
				int borne = (Integer)l.get(2);
				String interateur = (String)l.get(0);
				o.add(listToString((ArrayList)v.get(1)));
			
				int pas = 1; 
				
				if(l.size() == 4)
					pas = (Integer)l.get(3);
				
				for(int n = (Integer)l.get(1); n<borne; n+=pas) {
					penv.put(interateur,n);
					ret = run(o,env);
				}
				penv.remove(interateur);
			}	
		}
		return ret;	
	}
	
	
	}
